#ifndef _ACE_MESH_RUNTIME_
#define _ACE_MESH_RUNTIME_

typedef int Error_Code;
#define ACEMESH_OK  0

//NEIGHBOR relationship
#define NEIGHBOR_NONE      0x00000000
#define NEIGHBOR_UP        0x00000001
#define NEIGHBOR_DOWN      0x00000002
#define NEIGHBOR_LEFT      0x00000004
#define NEIGHBOR_RIGHT     0x00000008
#define NEIGHBOR_FRONT     0x00000010
#define NEIGHBOR_BACK      0x00000020
#define NEIGHBOR_ALL       0x0000ffff

//the read/write flag for addr
#define INOUT_NONE 0
#define IN         1
#define OUT        2
#define INOUT      3

//the type flag for the area that stands for by addr
#define NORMAL               1 
#define SHADE                2
#define UNSHADE              3
#define SHADE_AND_UNSHADE    4

//for task type
// typedef int task_type;
#define NOT_SET 0
#define STENCIL_TASK    1
#define NOAFFINITY_TASK 2
#define BLOCKING_TASK 3   //for mpi_wait, or mpi_send,mpi_recv etc blocking ops.
#define COMPOSITE_TASK 4
#define COMPOSITE_END_TASK 5
//end

#define RTS_undefined_event "21"
#define RTS_event_end "00"

  Error_Code begin_split_task_charPara(char * loop_info);
  Error_Code begin_split_task_zeroPara();
  Error_Code end_split_task_zeroPara();

  void spawn_and_wait();
  void spawn_and_wait(int print_graph);
  extern  void slave_init_array_map_table(int i,void * addr,...);

void aceMesh_MPI_rank(int rank);
void acemesh_mpi_rank(int rank);


/* *********************************
 * Sveral interfaces for clang     *
 * Author: Han Dong Ni             *
 * Date : 2013-12-31               *
 * *********************************/


typedef void (*TASK_FUNCPTR)(void *args);
#ifndef SWF
typedef void (*NEIGHBOR_FUNCPTR)(void** neighbor_addrs, int *num_neigh, void* args);
#else
  typedef void (*NEIGHBOR_FUNCPTR)(void *args);
#endif

void acemesh_runtime_init(int total_threads);
void acemesh_runtime_shutdown();
//Acemesh task generator
void acemesh_task_generator(void* taskfptr,void* args,  unsigned int args_size);
void acemesh_task_generator_with_neighbors(void *taskfptr, void *args, unsigned int args_size,
                                           void *cxx_this_pointer, void *get_neighbors_funcptr,
                                           void *neighbor_args);
#ifdef DOUBLE_FUNC
void acemesh_task_generator_msfunc(void *mtaskfptr, void *staskfptr, void *args, unsigned int args_size);
void acemesh_task_generator_with_neighbors_msfunc(void *mtaskfptr, void *staskfptr, void *args,
                                                      unsigned int args_size,
                                                      void *cxx_this_pointer,
                                                      void *get_neighbors_funcptr,
                                                      void *neighbor_args);
#endif
void acemesh_composite_task_generator(void *taskfptr, void *args, unsigned int args_size);
void acemesh_composite_task_generator_with_neighbors(void *taskfptr, void *args,
                                                     unsigned int args_size, void *cxx_this_pointer,
                                                     void *get_neighbors_funcptr,
                                                     void *neighbor_args);

void acemesh_specify_end_tasks();

void slave_acemesh_wait_reply(int *reply,int count);
int slave_acemesh_athread_get(int mode, void *src, void *dest, int len, void *reply, int mask,
                              int stride, int bsize);
int slave_acemesh_athread_put(int mode, void *src, void *dest, int len, void *reply, int stride,
                              int bsize);

//void acemesh_register_invalidatetab(void* array_addr, int ndim, int* tile_no,int itt);
//Handler for #pragma acemesh data clause
void acemesh_push_wrlist(int argc, void *addr, int access_flag, ...);
void acemesh_push_rlist(int argc, void *addr, int access_flag, ...);
void acemesh_push_wlist(int argc, void *addr, int access_flag, ...);

#ifdef REUSE_GRAPH
int acemesh_dag_start_vec(int dagNo, int *int_vec, int n1, double *float_vec, int n2);
int acemesh_dag_start(int dagNo);
#endif

void acemesh_begin_split_task(char *loop_info);
void acemesh_end_split_task();
void acemesh_spawn_and_wait(int print_graph);	
void acemesh_spawn_and_goout();	

#ifdef CONCURRENT_CONSTRUCT_GRAPH
void acemesh_wait_for_all_task();
#endif

#ifdef THREAD_TRACE
void acemesh_trace_print(const char event_name[]);
void slave_acemesh_trace_print(const char event_name[]);
#endif

void *acemesh_malloc_obj(unsigned int args_size);

//control task attributes (for the ci_task just now generated)
void acemesh_task_set_type(int type);
void acemesh_task_set_affinity(int id);

void acemesh_push_neighbor_addr(void *addr);
void acemesh_task_generator_swf2(void* taskfptr,  void* args,  unsigned int args_size);
void acemesh_task_generator_with_neighbors_swf2(void *task_funcptr, void *args,
                                                unsigned int args_size, void *cxx_this_pointer,
                                                void *neighbor_task_funcptr, void *neighbor_args);

int acemesh_get_loop_tile_num(int loop_tile_size, int loop_index_lb, int loop_index_ub);
int acemesh_get_loop_tile_start_index_by_tile_no(int loop_tile_size, int loop_tile_no,
                                                 int loop_index_lb);
int acemesh_get_loop_tile_end_index_by_tile_no(int loop_tile_size, int loop_tile_no,
                                               int loop_index_lb, int loop_index_ub);
int acemesh_get_data_tile_start_index_by_index(int data_tile_size, int compute_index,
                                               int array_dim_lb);
void * slave_acemesh_ldm_malloc(int size);
void slave_acemesh_ldm_free(void *addr, int size);
int slave_acemesh_get_allocatable_size();
void acemesh_task_map_master();
#ifdef MPI_SURPPORT
void acemesh_set_suspend(int mode);
#endif
void acemesh_set_thread_num(int thread_num);
//void set_task_suspend(struct aceMesh_task *self, int mode);

#endif
